home *** CD-ROM | disk | FTP | other *** search
-
- static char RCSId[]="$Id: Gnuplot.m,v 1.1.1.1 1993/03/18 03:33:26 davis Exp $";
-
-
- #import <appkit/Application.h>
- #import <appkit/Listener.h>
- #import <appkit/Matrix.h>
- #import <appkit/Menu.h>
- #import <appkit/MenuCell.h>
- #import <appkit/OpenPanel.h>
- #import <appkit/PrintInfo.h>
- #import <appkit/Speaker.h>
-
- #import <appkit/publicWraps.h> /* NXConvertWinNumToGlobal() */
-
- #import <objc/List.h>
- #import <objc/NXStringTable.h>
-
- #import <libc.h> /* MAXPATHLEN */
- #import <strings.h> /* strcmp() */
-
- #import "Gnuplot.h"
- #import "GnuplotPlot.h"
- #import "Inspector.h"
- #import "Preferences.h"
-
-
-
-
- /*
- * This function is from the NeXTSTEP Developer Example Draw by Paul
- * Hegarty.
- *
- * Sets the updateAction for every menu item that sends its action to
- * the First Responder (i.e. every menu item whose target is nil).
- * When autoupdate is on (which is always in this app), each event
- * will be followed by an update of every visible menu item. This
- * keeps all unavailable menu items dimmed and disabled so that the
- * user knows what options are available at any given time.
- */
- static void initMenu (Menu* menu)
- {
- int count;
- Matrix *matrix;
- MenuCell *cell;
- id matrixTarget, cellTarget;
-
- matrix = [menu itemList];
- matrixTarget = [matrix target];
-
- count = [matrix cellCount];
- while (count--) {
-
- cell = [matrix cellAt:count :0];
- cellTarget = [cell target];
-
- if (!matrixTarget && !cellTarget)
- [cell setUpdateAction:@selector(menuItemUpdate:) forMenu:menu];
- else if ([cell hasSubmenu])
- initMenu(cellTarget);
-
- }
- }
-
-
-
-
- @implementation Gnuplot
-
- + setConstantUpdate:(int)updateType
- {
- return [GnuplotPlot setConstantUpdate:updateType];
- }
-
-
- + setHalvePlot:(BOOL)condition
- {
- return [GnuplotPlot setHalvePlot:condition];
- }
-
-
- + setAddDataToCurrentEnabled:(BOOL) aBool
- {
- NXSetServicesMenuItemEnabled("Gnuplot/Add Data to Current Plot", aBool);
- return self;
- }
-
-
- + setAddDataToNewEnabled:(BOOL) aBool
- {
- NXSetServicesMenuItemEnabled("Gnuplot/Plot Data in New Plot", aBool);
- return self;
- }
-
-
-
- - init
- {
- [super init];
-
- zone = [self zone];
-
- docList = [[List allocFromZone: zone] init];
- numUntitled = 1;
- isPoweringOff = NO;
-
- /* Set printinfo margins to 1/2 inch (36 points) on each side */
- [[NXApp printInfo] setMarginLeft:36.0 right:36.0 top:36.0 bottom:36.0];
-
- [NXApp setAutoupdate:YES];
-
- preferences = [[Preferences allocFromZone: zone] init];
- inspector = [[Inspector allocFromZone: zone] init];
-
- return self;
- }
-
-
-
- - stringSet
- {
- return stringSet;
- }
-
-
- - showInfoPanel:sender
- {
- /* Updated automatically by RCS */
- static char *rev = NULL;
-
- if (!rev) {
- rev = NXCopyStringBufferFromZone ("$Revision: 1.1.1.1 $", zone);
- *(rindex (rev, '$')) = '\0';
- }
-
- if (!infoPanel)
- [NXApp loadNibSection: "InfoPanel.nib"
- owner: self
- withNames: NO
- fromZone: zone];
-
- [revisionTextField setStringValue: rev + 11];
- [infoPanel makeKeyAndOrderFront:self];
-
- return self;
- }
-
-
-
- - showCopyingPanel:sender
- {
- if (!copyingPanel)
- [NXApp loadNibSection: "CopyingPanel.nib"
- owner: self
- withNames: NO
- fromZone: zone];
-
- [copyingPanel makeKeyAndOrderFront:self];
-
- return self;
- }
-
-
-
- - showInspectorPane:sender
- {
- /* Inspector was created in -init */
-
- [inspector selectPane:[sender selectedTag]];
- [[inspector window] makeKeyAndOrderFront:self];
- return self;
- }
-
-
-
- - showPreferencesPanel:sender
- {
- /* Preferences was created in -init */
-
- [preferences showPanel:self];
- return self;
- }
-
-
-
- - new:sender
- {
- id newDoc = nil;
-
- if (newDoc = [[GnuplotPlot allocFromZone: zone] init]) {
- numUntitled++;
- [docList addObject:newDoc];
- }
-
- return newDoc;
- }
-
-
-
- - open:sender
- {
- const char *const *files;
- static const char *const fileType[2] = {DOCUMENT_TYPE, NULL};
- OpenPanel *openPanel;
- id newDoc;
- char fullName[MAXPATHLEN];
-
- openPanel = [[OpenPanel new] allowMultipleFiles:YES];
-
- /* Get a list of files to open from the user. */
- if ([openPanel runModalForTypes:fileType]) {
-
- /* For each pathname selected... */
- for (files = [openPanel filenames]; files && *files; files++) {
-
- sprintf (fullName, "%s/%s", [openPanel directory], *files);
-
- /*
- * ... check to see if the doc is already opened. If it
- * is, bring it to the front.
- */
- if (newDoc = [self isDocOpen: fullName])
- [[newDoc window] makeKeyAndOrderFront:self];
-
- /* If not, try to create a new one. */
- else if ((newDoc = [[GnuplotPlot allocFromZone: zone]
- initFromFile: fullName]))
- [docList addObject: newDoc];
-
-
- /*
- * Otherwise, just return. GnuplotPlot will report the
- * nature of the error to the user so we don't need to
- * here.
- */
- else
- return nil;
-
- }
-
- }
-
- return self;
- }
-
-
-
-
- - saveAll:sender
- {
- [docList makeObjectsPerform:@selector(save:) with:self];
- return self;
- }
-
-
-
- /*
- * This method should update any panels external to the doc which
- * reflect the current doc (e.g. the Inspector panel).
- */
- - updateApp
- {
- [inspector update];
- return self;
- }
-
-
-
-
- /*
- * The doc should send this when it closes so that we can remove it
- * from our doc list.
- */
- - docDidClose:sender
- {
- [docList removeObject:sender];
- [self setCurrentDoc:nil];
- return self;
- }
-
-
-
- /*
- * Checks the doc list to see if the doc specified by fullPath is
- * currently open. If it is, the doc is returned. Otherwise, nil is
- * returned.
- */
- - isDocOpen: (const char *) fullPath
- {
- int counter, docCount = [docList count];
- id aDoc;
-
- for (counter = 0 ; counter < docCount ; counter++)
- if (!strcmp ([aDoc = [docList objectAt: counter] name], fullPath))
- return aDoc;
-
- return nil;
- }
-
-
-
-
- - (int)numberNew
- {
- return numUntitled;
- }
-
-
-
- - setCurrentDoc:aDoc
- {
- if (aDoc)
- currentDoc = aDoc;
- else
- currentDoc = [[NXApp mainWindow] delegate];
-
- return self;
- }
-
-
-
-
- /*** Auto-Update Methods ***/
-
-
-
- /*
- * This method is from the NeXTSTEP example Draw by Paul Hegarty.
- *
- * When a menu is updated, this method is sent by each menu item that
- * sends its action to the First Responder. If the object that would
- * respond to an action sent down the Responder chain also responds
- * to the validateCommand:, then we send validateCommand: to
- * determine whether the menu action is valid now. Otherwise, if
- * there is a Responder to the message, then we assume that the item
- * is valid. The method returns YES if the cell has changed its
- * appearance (so that the caller Menu knows to redraw it).
- */
- - (BOOL)menuItemUpdate:menuCell
- {
- SEL action;
- id responder, target;
- BOOL enable;
-
- target = [menuCell target];
- enable = [menuCell isEnabled];
-
- if (!target) {
- action = [menuCell action];
- responder = [NXApp calcTargetForAction:action];
- if ([responder respondsTo:@selector(validateCommand:)])
- enable = [responder validateCommand:menuCell];
- else
- enable = responder ? YES : NO;
-
- }
-
- if ([menuCell isEnabled] != enable) {
- [menuCell setEnabled:enable];
- return YES;
- } else
- return NO;
-
- }
-
-
- /*
- * This method is sent down the Responder chain by menuItemUpdate:
- *
- * Every object that responds to messages sent down the Responder
- * chain by menu cells but occasionally can't do perform the action
- * should implement validateCommand: and return a boolean value
- * telling whether the menu item should be enabled or not.
- *
- * For example: we can respond to saveAll:, but we can't save all if
- * there are no docs that need saving. So we need to implement
- * validateCommand: to disable the saveAll: menu cell when it is
- * irrelevant.
- */
- - (BOOL)validateCommand:menuCell
- {
- SEL action = [menuCell action];
- int count;
-
- if (action == @selector(saveAll:)) {
-
- if ([docList count])
- for (count = [docList count] - 1; count >= 0 ; count--)
- if ([[docList objectAt:count] validateCommand:menuCell])
- return YES;
-
- return NO;
-
- }
-
- return YES;
- }
-
-
-
-
-
-
-
- /*** Application Delegate Methods ***/
-
-
- /* Sent when user opens one of our docs from the Workspace. */
-
- - (int)app:sender openFile:(const char *)path type:(const char *)type
- {
- id newObject;
-
- /* If the document is of the right type... */
- if (type && !strcmp (type, DOCUMENT_TYPE)) {
-
- /*
- * ... first check to see if it's already open. If it is,
- * bring it to the front.
- */
- if (newObject = [self isDocOpen: path])
- [[newObject window] makeKeyAndOrderFront:self];
-
-
- /* Otherwise, attempt to open the document. */
- else if (newObject = [[GnuplotPlot allocFromZone: zone]
- initFromFile:path]) {
-
- [docList addObject:newObject];
-
- /*
- * Set the OpenPanel directory so that when the user opens
- * another doc, the open panel will start where he/she left
- * off.
- */
- [[OpenPanel new] setDirectory:path];
-
- /*
- * This causes documents opened from the Workspace to
- * open more slowly, but if we don't the Inspector will
- * be outdated until the next event.
- */
- [self updateApp];
- return YES;
-
- }
-
- }
-
- return NO;
- }
-
-
- - app:sender powerOffIn:(int)ms andSave:(int)aFlag
- {
- isPoweringOff = YES;
- return [self appWillTerminate:self];
- }
-
-
-
- - (BOOL)appAcceptsAnotherFile:sender
- {
- /*
- * We return YES to this because we can open any number of
- * documents.
- */
- return YES;
- }
-
-
- - appDidInit:sender
- {
- initMenu([NXApp mainMenu]); /* Setup auto-menu-update */
-
- /*
- * Set services delegate to be self so this app can be a
- * service-provider and this object can handle the messages.
- */
- [[NXApp appListener] setServicesDelegate:self];
-
-
- /*
- * Open a new, untitled document, unless the app was started when
- * the user opened a document from the Workspace or the user has
- * specified not to with Preferences.
- */
- if (![docList count] && [preferences newDocument])
- [self new:self];
-
- /*
- * We make the inspector the key window down here, last, so that
- * it will be key when the user begins using the program. The
- * user can begin working without necessarily needing to use the
- * mouse. We also select the user's prefered pane.
- */
- [inspector selectPane: [preferences defaultInspector]];
- [[inspector window] makeKeyAndOrderFront:self];
-
- return self;
- }
-
-
-
- - appWillTerminate: sender
- {
- int editedCount, counter;
- id editedDocs = [[List allocFromZone: zone] init];
- id aDoc;
-
- do {
-
- /* Build a list of edited, unsaved docs. */
-
- [editedDocs empty];
- counter = [docList count];
- while (--counter >= 0) {
- aDoc = [docList objectAt: counter];
- if ([aDoc isDocEdited])
- [editedDocs addObject: aDoc];
- }
-
- /*
- * If there are edited, unsaved docs, ask if the user wants to
- * review them, quit, or cancel the quit action (unless this
- * method was sent by us during a poweroff/logoff, in which
- * case we don't allow a cancel).
- */
- if ((editedCount = [editedDocs count]) > 0) {
- switch (NXRunAlertPanel ([stringSet valueForStringKey: "quitT"],
- [stringSet valueForStringKey: "unsavedDocs"],
- [stringSet valueForStringKey: "reviewB"],
- [stringSet valueForStringKey: "quitB"],
- isPoweringOff? NULL: [stringSet valueForStringKey: "cancelB"])) {
-
- case NX_ALERTDEFAULT: /* Review Unsaved */
-
- counter = editedCount;
- while (--counter >= 0)
- [[editedDocs objectAt: counter] close:self];
- break;
-
- case NX_ALERTALTERNATE: /* Quit Anyway */
- editedCount = 0;
- break;
-
- case NX_ALERTOTHER: /* Cancel */
- [editedDocs free];
- return nil;
- break;
- }
- }
-
- /*
- * If the user chooses to review unsaved, then is shown a Save
- * panel for a doc and chooses "Cancel," we end up down here,
- * where we'll repeat if there are more unedited docs.
- * Basically, we force the user either to save all the docs or
- * make a decision in the quit panel to review, quit, or
- * cancel.
- */
-
- } while (editedCount > 0);
-
- [editedDocs free];
-
-
- /*
- * Quit the application. (We free things here because -free is
- * never called -- NXApp simply exit()'s -- but GnuplotPlot's
- * implementation of -free deletes the plot's tmp file, so we
- * must call it to avoid leaving junk in /tmp.)
- */
-
- [docList makeObjectsPerform: @selector(free)];
- [docList free];
-
- return self;
- }
-
-
-
- /*
- * This method is sent when a user chooses one of Gnuplot's services
- * from the Services menu in another application.
- */
- - plotData:pb userData:(const char *)userData error:(char **)errorMessage
- {
- char *data;
- int length, i;
- const char *const *types;
- BOOL hasFilename;
-
- types = [pb types];
- hasFilename = NO;
- for (i=0 ; !hasFilename && types[i] ; i++)
- if (!strcmp (types[i], NXFilenamePboardType)) hasFilename = YES;
- if (hasFilename) {
- [pb readType:NXFilenamePboardType data:&data length:&length];
-
- if (data && length) {
- char *path;
-
- path = (char *) malloc (length + 1);
- strncpy (path, data, length);
- path[length] = '\0';
-
- /*
- * If there is a current document, we add the data file
- * specified on the pasteboard to it. If there's no
- * current document, or if the userData contains "new"
- * we create a new document and add the data file to
- * that.
- */
-
- if (currentDoc && strcmp (userData, "new"))
- [currentDoc addDataFile:path];
- else
- [[self new:self] addDataFile:path];
-
- [self updateApp];
-
- }
- }
-
- return self;
- }
-
-
- // Shuts up the compiler about unused RCSId
- - (const char *) rcsid
- {
- return RCSId;
- }
-
-
- @end
-
-